# Author ： chosen-yn
from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework_simplejwt.tokens import RefreshToken
from utils.common_reponse import APIResponse
from user.models import User
from django.conf import settings
from django.core.cache import cache
from faker import Faker
from pypinyin import pinyin, Style
import re


class LoginSerializer(serializers.Serializer):
    def _get_user(self, attrs):
        raise APIException(detail='这个方法必须重写')

    def _get_token(self, user):
        refresh = RefreshToken.for_user(user)
        return str(refresh.access_token)

    def _get_data(self, token, user):
        self.context['username'] = user.username
        self.context['token'] = token
        # 因为 icon是文件对象不能直接给的，所以要配置一下
        self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon)

    def validate(self, attrs):
        # 1 取出用户名(手机号，邮箱)和密码，校验用户
        user = self._get_user(attrs)
        # 2 如果存在：签发token,返回
        token = self._get_token(user)
        # 3 把 token，用户名和 icon放入 context
        self._get_data(token, user)
        return attrs


# 序列化类干什么用？只做校验 --》继承 Serializer
# 因为如果继承 ModelSerializer---》字段是映射过来的 --》字段的校验规则也会被映射过来。
# 由于 username 字段上有 unique --》 所以走字段自己的校验规则会失败 ---》必须要重写username

class MulLoginSerializer(LoginSerializer):
    username = serializers.CharField(max_length=32, min_length=1)
    password = serializers.CharField(max_length=32, min_length=5)

    def _get_user(self, attrs):
        # 1 取出username和password
        username = attrs.get('username')
        password = attrs.get('password')
        # 2 判断username 是手机号？ 邮箱？ 用户名？
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(mobile=username).first()

        elif re.match('^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', username):
            user = User.objects.filter(email=username).first()

        else:
            user = User.objects.filter(username=username).first()

        # 判断是否都是正确的
        if user and user.check_password(password):
            return user
        else:
            raise APIException(detail='用户名或密码错误')


class SMSLoginSerializer(LoginSerializer):
    mobile = serializers.CharField(max_length=11, min_length=11)
    code = serializers.CharField(max_length=4, min_length=4)

    def _get_user(self, attrs):
        # 1 取出 code 和 mobile
        code = attrs.get('code')
        mobile = attrs.get('mobile')

        # 2 取出 缓存中的 old_code
        old_code = cache.get(f'sms_{mobile}')

        # 3 判断验证码是否正确 -- 自己留了一个后门，但是没有人要求留后门，就不要留
        if old_code == code or (settings.DEBUG and code == '8888'):
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise APIException(detail='手机号不存在')
        else:
            raise APIException(detail='验证码错误')


class RegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=4, min_length=4)

    class Meta:
        model = User
        fields = ['password', 'code', 'mobile']

    ## 生成随机名字
    def generate_name(self):
        fake = Faker(['zh-cn'])
        name = fake.name()
        pinyin_name = ''.join([item[0] for item in pinyin(name, style=Style.NORMAL)])
        return pinyin_name

    def validate(self, attrs):
        # 1 校验 code
        mobile = attrs.get('mobile')
        code = attrs.pop('code')
        old_code = cache.get(f'sms_{mobile}')
        assert old_code == code or (settings.DEBUG and code == '8888'), APIException('验证码错误')

        # 2 User表 中字段很多，有的必填：username字段 1 使用手机号作为用户名 2 随机生成一个用户名（fake--》生成一个用户名，pinyin--》把中文汉字转成拼音）
        # 手机号作为用户名
        # attrs['username'] = mobile  # 使用手机号作为用户名
        attrs['username'] = self.generate_name()

        return attrs

    # 重写 create方法 ，因为密码从前端传进来是明文的，必须使用 create_user创建用户
    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

# # 序列化类干什么用？只做校验 --》继承 Serializer
# # 因为如果继承 ModelSerializer---》字段是映射过来的 --》字段的校验规则也会被映射过来。
# # 由于 username 字段上有 unique --》 所以走字段自己的校验规则会失败 ---》必须要重写username
#
# class MulLoginSerializer(serializers.Serializer):
#     username = serializers.CharField(max_length=32, min_length=1)
#     password = serializers.CharField(max_length=32, min_length=5)
#
#     def _get_user(self, attrs):
#         # 1 取出username和password
#         username = attrs.get('username')
#         password = attrs.get('password')
#         # 2 判断username 是手机号？ 邮箱？ 用户名？
#         if re.match(r'^1[3-9][0-9]{9}$', username):
#             user = User.objects.filter(mobile=username).first()
#
#         elif re.match('^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', username):
#             user = User.objects.filter(email=username).first()
#
#         else:
#             user = User.objects.filter(username=username).first()
#
#         # 判断是否都是正确的
#         if user and user.check_password(password):
#             return user
#         else:
#             raise APIException(detail='用户名或密码错误')
#
#     def _get_token(self, user):
#         refresh = RefreshToken.for_user(user)
#         return str(refresh.access_token)
#
#     def _get_data(self, token, user):
#         self.context['username'] = user.username
#         self.context['token'] = token
#         # 因为 icon是文件对象不能直接给的，所以要配置一下
#         self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon)
#
#     def validate(self, attrs):
#         # 1 取出用户名(手机号，邮箱)和密码，校验用户
#         user = self._get_user(attrs)
#         # 2 如果存在：签发token,返回
#         token = self._get_token(user)
#         # 3 把 token，用户名和 icon放入 context
#         self._get_data(token, user)
#         return attrs
#
#
# class SMSLoginSerializer(serializers.Serializer):
#     mobile = serializers.CharField(max_length=11, min_length=11)
#     code = serializers.CharField(max_length=4, min_length=4)
#
#     def _get_user(self, attrs):
#         # 1 取出 code 和 mobile
#         code = attrs.get('code')
#         mobile = attrs.get('mobile')
#
#         # 2 取出 缓存中的 old_code
#         old_code = cache.get(f'sms_{mobile}')
#
#         # 3 判断验证码是否正确 -- 自己留了一个后门，但是没有人要求留后门，就不要留
#         if old_code == code or (settings.DEBUG and code == '8888'):
#             user = User.objects.filter(mobile=mobile).first()
#             if user:
#                 return user
#             else:
#                 raise APIException(detail='手机号不存在')
#         else:
#             raise APIException(detail='验证码错误')
#
#     def _get_token(self, user):
#         refresh = RefreshToken.for_user(user)
#         return str(refresh.access_token)
#
#     def _get_data(self, token, user):
#         self.context['username'] = user.username
#         self.context['token'] = token
#         # 因为 icon是文件对象不能直接给的，所以要配置一下
#         self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon)
#
#     def validate(self, attrs):
#         # 1 取出用户名(手机号，邮箱)和密码，校验用户
#         user = self._get_user(attrs)
#         # 2 如果存在：签发token,返回
#         token = self._get_token(user)
#         # 3 把 token，用户名和 icon放入 context
#         self._get_data(token, user)
#         return attrs
#
#
# class RegisterSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = User
#         fields = ['username', 'password', 'email', 'mobile']
#
#     def create(self, validated_data):
#         password = validated_data.pop('password')
#         new_password = make_password(password=password)
#         user = User.objects.create_user(**validated_data, password=new_password)
#         return user
